#ifndef LSV_LIB_H
#define LSV_LIB_H

#include <string.h>
#include <stdlib.h>
#include <time.h>

#include "lsv_conf.h"
#include "sysutil.h"
#include "sysy_lib.h"
#include "dbg.h"
#include "mem_pool.h"

#define OFF2LBA(off) ((off) - (off) % LSV_PAGE_SIZE)

typedef struct {
        uint64_t count1;
        uint64_t count2;
} count_pair_t;

typedef enum {
        COUNT_BITMAP_IN  = 0,
        COUNT_BITMAP_OUT = 1,

        COUNT_LOG_IN  = 2,
        COUNT_LOG_OUT = 3,

        COUNT_MAX,
} count_type_t;

typedef struct {
        char name[MAX_NAME_LEN];
        struct timeval time1, time2;
        uint64_t interval; // us
        count_pair_t pairs[COUNT_MAX];
} time_count_t;

static inline void time_count_init(time_count_t *tc, const char *name, uint64_t interval) {
        strcpy(tc->name, name);

        _gettimeofday(&tc->time1, NULL);
        _gettimeofday(&tc->time2, NULL);

        tc->interval = interval;

        memset(tc->pairs, 0, sizeof(count_pair_t)*COUNT_MAX);
}

static inline void time_count_update(time_count_t *tc, count_type_t t, uint64_t count) {
        _gettimeofday(&tc->time2, NULL);
        tc->pairs[t].count2 += count;

        int64_t used = _time_used(&tc->time1, &tc->time2);
        if (used >= tc->interval) {
                for (int i=0; i < COUNT_MAX; i++) {
                        uint64_t delta = tc->pairs[i].count2 - tc->pairs[i].count1;
                        DERROR("%s %d time %llu count %llu %llu %llu iops %llu\n", tc->name, i,
                               (LLU)used,
                               (LLU)tc->pairs[i].count1,
                               (LLU)tc->pairs[i].count2,
                               (LLU)delta,
                               (LLU)delta * 1000000/used);
                }

                // update all
                tc->time1 = tc->time2;
                for (int i=0; i < COUNT_MAX; i++) {
                        tc->pairs[i].count1 = tc->pairs[i].count2;
                }
        }
}

// from lsv_page.c
int lsv_page_num(uint64_t off, uint32_t size);

static inline int is_page_aligned(uint64_t off, uint32_t size) {
        return (off % LSV_PAGE_SIZE == 0 && (off + size) % LSV_PAGE_SIZE == 0);
}

static inline uint32_t page_crc32(const void *ptr) {
#if 1
        return crc32_sum(ptr, LSV_PAGE_SIZE);
#else
        return 0;
#endif
}

typedef struct {
        uint64_t count;
        uint64_t used;
} op_stat_t;

typedef enum {
        MALLOC_CHUNK = 0,

        WRITE_4K,
        WRITE_8K,
        WRITE_1M,

        WRITE_BITMAP,

        OP_MAX,
} op_type_t;

static inline uint64_t used_per_op(op_stat_t *stat) {
        if (stat->count == 0) {
                return 0;
        }
        return stat->used / stat->count;
}

void check_bitmap_alloc(void **context, uint64_t capacity);
void check_bitmap_free(void *context);
void check_bitmap_set(void *context, uint64_t off, void * buf);
void check_bitmap_check(void *context, uint64_t off, void * buf);

void lsv_memory_destory();

static inline void * lsv_malloc(uint32_t size)
{
        mem_pool_t *mem_pool = mem_pool_get(MEMORY_TYPE_INDEX_LSV); //todo.
        return mem_pool_alloc(mem_pool, size);
}

static inline void lsv_free(void *ptr)
{
        mem_pool_t *mem_pool = mem_pool_get(MEMORY_TYPE_INDEX_LSV); //todo.

        mem_pool_free(mem_pool, ptr);
}

static inline void *xmalloc(size_t sz)
{
#if LSV_USE_HUGE_PAGE
        return lsv_malloc(sz);
#else
        void *p;
        int ret;

        ret = ymalloc(&p, sz);
        if(unlikely(ret))
                return NULL;
        else
                return p;
#endif
}

static inline void xfree(void *p)
{
#if LSV_USE_HUGE_PAGE
        lsv_free(p);
#else
        yfree(&p);
#endif
}

#endif
